
import Foundation
import UIKit
import Metal
import MetalKit

class HYMTKView: MTKView {
    override init(frame frameRect: CGRect, device: MTLDevice?) {
        super.init(frame: frameRect, device: device)
        self.framebufferOnly = false
        self.enableSetNeedsDisplay = true
        if device == nil {
            self.device = MTLCreateSystemDefaultDevice()
        }
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

public protocol HYSlideShowDelegate {
    var imageNames: [String] { get }
}


public class HYSlideShow: UIView {
    private var scrollView: UIScrollView!
    private var leftImageView: MTKView!
    private var rightImageView: MTKView!
    private var centerImageView: MTKView!
    private var leftImageRender: Render!
    private var rightImageRender: Render!
    private var centerImageRender: Render!
    private var delegate: HYSlideShowDelegate!
    private var beginOffset = CGPoint.zero
    private var currentShowIndex = 0
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    public init(frame: CGRect, delegate: HYSlideShowDelegate) {
        super.init(frame: frame)
        self.delegate = delegate
        initUI(frame: frame)
    }
}

// MARK: - Private Method
extension HYSlideShow {
    private func initUI(frame: CGRect) {
        let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
        scrollView.delegate = self
        scrollView.isPagingEnabled = true
        scrollView.contentOffset = CGPoint(x: frame.width, y: 0)
        
        addSubview(scrollView)
        let width = frame.width
        let height = frame.height
        scrollView.contentSize = CGSize(width: width * 3, height: height)
        let leftImageView = HYMTKView(frame: CGRect(x: 0, y: 0, width: width, height: height))
        leftImageRender = Render(leftImageView)
        leftImageRender.updateTexture(name: delegate.imageNames[3])
        leftImageRender.mtkView(leftImageView, drawableSizeWillChange: leftImageView.drawableSize)
        scrollView.addSubview(leftImageView)
        let rightImageView = HYMTKView(frame: CGRect(x: width * 2, y: 0, width: width, height: height))
        rightImageRender = Render(rightImageView)
        rightImageRender.updateTexture(name: delegate.imageNames[1])
        rightImageRender.mtkView(rightImageView, drawableSizeWillChange: rightImageView.drawableSize)
        scrollView.addSubview(rightImageView)
        let centerImageView = HYMTKView(frame: CGRect(x: width, y: 0, width: width, height: height))
        centerImageRender = Render(centerImageView)
        centerImageRender.updateTexture(name: delegate.imageNames[0])
        centerImageRender.mtkView(centerImageView, drawableSizeWillChange: centerImageView.drawableSize)
        scrollView.addSubview(centerImageView)
    }
}

// MARK: - UIScrollViewDelegate
extension HYSlideShow: UIScrollViewDelegate {
    
    public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        beginOffset = scrollView.contentOffset
    }
    
    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("scrollViewDidEndDecelerating")
        let dx = scrollView.contentOffset.x - beginOffset.x
        
        if abs(dx) < frame.width / 2 {
            return
        }
        
        if dx > 0 { // scroll right
            var rightIndex = imageIndex(isScrollToRight: true, currentIndex: currentShowIndex)
            rightIndex = imageIndex(isScrollToRight: true, currentIndex: rightIndex)
            rightImageRender.updateTexture(name: delegate.imageNames[rightIndex])
            leftImageRender.updateTexture(name: delegate.imageNames[currentShowIndex])
            let centerIndex = imageIndex(isScrollToRight: true, currentIndex: currentShowIndex)
            centerImageRender.updateTexture(name: delegate.imageNames[centerIndex])
        } else { // scroll left
            rightImageRender.updateTexture(name: delegate.imageNames[currentShowIndex])
            var leftIndex = imageIndex(isScrollToRight: false, currentIndex: currentShowIndex)
            leftIndex = imageIndex(isScrollToRight: false, currentIndex: leftIndex)
            leftImageRender.updateTexture(name: delegate.imageNames[leftIndex])
            let centerIndex = imageIndex(isScrollToRight: false, currentIndex: currentShowIndex)
            centerImageRender.updateTexture(name: delegate.imageNames[centerIndex])
        }
        currentShowIndex = imageIndex(isScrollToRight: dx > 0, currentIndex: currentShowIndex)
        scrollView.contentOffset = CGPoint(x: frame.width, y: 0)
    }
}

extension HYSlideShow {
    private func imageIndex(isScrollToRight: Bool, currentIndex: Int) -> Int {
        let offset = isScrollToRight ? 1 : -1;
        var imageIndex = currentIndex + offset
        if imageIndex > delegate.imageNames.count - 1 {
            imageIndex = 0
        }
        if imageIndex < 0 {
            imageIndex = delegate.imageNames.count - 1
        }
        return imageIndex
    }
}
